package com.moyu.plugin.cat

import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor

/**
 * 自定义ASM ClassVisitor实现类，用于在类加载时插入方法拦截逻辑
 *
 * @param api                ASM API版本号
 * @param catOn              是否启用插件功能开关
 * @param classVisitor       下一个ClassVisitor实例（用于链式调用）
 */
class CatClassVisitor(
    api: Int,
    private val catOn: Boolean,
    classVisitor: ClassVisitor
) : ClassVisitor(api, classVisitor) {

    init {
        // 初始化时打印插件开关状态，用于调试
        println("load catOn $catOn")
    }

    // 保存当前处理的类名（使用lateinit因ASM保证visit方法会在.visitMethod前调用）
    private lateinit var mClassName: String

    /**
     * ASM类访问事件入口，当类被访问时触发
     *
     * @param version      类的版本号
     * @param access       类的访问权限标志
     * @param name         类的内部名称（如"Ljava/lang/Object;"）
     * @param signature    泛型签名（接口或泛型类）
     * @param superName    父类名称
     * @param interfaces   实现的接口列表
     */
    override fun visit(
        version: Int,
        access: Int,
        name: String,
        signature: String?,
        superName: String?,
        interfaces: Array<String>?
    ) {
        super.visit(version, access, name, signature, superName, interfaces)
        // 保存当前处理的类名，并打印类访问日志
        mClassName = name
        println("visit class $mClassName")
    }

    /**
     * 方法访问事件入口，当方法被访问时创建MethodVisitor
     *
     * @param access       方法访问权限标志
     * @param name         方法名称
     * @param desc         方法描述符（参数及返回类型）
     * @param signature    泛型签名（如存在泛型参数时）
     * @param exceptions   抛出的异常列表
     * @return 包装后的MethodVisitor实例
     */
    override fun visitMethod(
        access: Int,
        name: String,
        desc: String?,
        signature: String?,
        exceptions: Array<String>?
    ): MethodVisitor {
        // 获取原始MethodVisitor实例
        var methodVisitor = super.visitMethod(access, name, desc, signature, exceptions)

        if (catOn) {

            // 开关启用时，包装MethodVisitor为自定义CatMethodVisitor
            // 用于实现方法执行前后的插桩逻辑
            methodVisitor = CatMethodVisitor(
                api, methodVisitor, access, mClassName, name, desc
            )
            println("execute method visitor")
        } else {
            // 开关关闭时直接返回原始visitor
            println("do not execute method visitor")
        }

        return methodVisitor
    }
}